using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using WiimoteLib;

namespace WiimoteAnaylse
{
    public class Viewer : UserControl
    {
        bool resizing;
        Point resizePt;

        public Viewer()
        {
            BackColor = Color.Black;
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            UpdateStyles();
        }

        const int ResizeHandleSize = 10;

        public void DrawResizeHandle(Graphics g)
        {
            Rectangle r = ClientRectangle;
            Point l = new Point(r.Right - ResizeHandleSize, r.Bottom);
            Point t = new Point(r.Right, r.Bottom - ResizeHandleSize);
            while (l.X < r.Right)
            {
                g.DrawLine(Pens.White, l, t);
                l.Offset(2, 0);
                t.Offset(0, 2);
            }
        }

        bool HitResizeHandle(Point pt)
        {
            if (pt.X >= Width - ResizeHandleSize && pt.X <= Width &&
                pt.Y >= Height - ResizeHandleSize && pt.Y <= Height)
                return true;
            return false;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            DrawResizeHandle(e.Graphics);
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            if (HitResizeHandle(new Point(e.X, e.Y)))
            {
                resizing = true;
                resizePt = new Point(e.X, e.Y);
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (resizing)
            {
                Width += e.X - resizePt.X;
                Height += e.Y - resizePt.Y;
                resizePt = new Point(e.X, e.Y);
                if (Width < ResizeHandleSize)
                    Width = ResizeHandleSize;
                if (Height < ResizeHandleSize)
                    Height = ResizeHandleSize;
                // redraw resize handle
                Invalidate();
            }
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            resizing = false;
        }
    }

    public class IRViewer : Viewer
    {
        IRState irState;

        public void SetIRState(IRState irState)
        {
            this.irState = irState;
            Invalidate();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            // set graphics
            Graphics g = e.Graphics;
            // draw IR points
            if (irState.Found1)
                g.FillEllipse(Brushes.White, new RectangleF(Width * irState.X1, Height * irState.Y1,
                    irState.Size1 + 1, irState.Size1 + 1));
            if (irState.Found2)
                g.FillEllipse(Brushes.White, new RectangleF(Width * irState.X2, Height * irState.Y2,
                    irState.Size2 + 1, irState.Size2 + 1));
        }
    }

    public class AccelViewer : Viewer
    {
        AccelState accelState;

        public void SetAccelState(AccelState accelState)
        {
            this.accelState = accelState;
            Invalidate();
        }

        PointF RotatePoint(PointF pt, PointF origin, double angle)
        {
            if (angle == 0)
                return pt;
            // set to origin
            pt = new PointF(pt.X - origin.X, pt.Y - origin.Y);
            // rotate point
            PointF rotatedPt = new PointF((float)(pt.X * Math.Cos(angle) - pt.Y * Math.Sin(angle)),
                                          (float)(pt.X * Math.Sin(angle) + pt.Y * Math.Cos(angle)));
            // unset from origin
            rotatedPt = new PointF(rotatedPt.X + origin.X, rotatedPt.Y + origin.Y);
            return rotatedPt;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            // set graphics
            Graphics g = e.Graphics;
            // draw Accel vectors
            PointF cpt = new PointF(Width / 2f, Height / 2f);
            int div = 2;
            double _30deg = -Math.PI / 4 * 2 / 3;
            double _60deg = -Math.PI / 4 * 4 / 3;
            float r = Math.Min(Width, Height);
            PointF xpt = new PointF(cpt.X + (r / 2) * (accelState.X / div), cpt.Y);
            xpt = RotatePoint(xpt, cpt, _30deg);
            PointF ypt = new PointF(cpt.X, cpt.Y + (r / 2) * (accelState.Y / div));
            ypt = RotatePoint(ypt, cpt, _60deg);
            PointF zpt = new PointF(cpt.X, cpt.Y + (r / 2) * (accelState.Z / div));
            g.DrawLine(Pens.Red, cpt, xpt);
            g.DrawLine(Pens.Green, cpt, ypt);
            g.DrawLine(Pens.Blue, cpt, zpt);
            // draw reference arrow
            PointF arrowTip = RotatePoint(new PointF(cpt.X + 10, cpt.Y + 50), cpt, _60deg);
            PointF arrowL = RotatePoint(new PointF(cpt.X, cpt.Y + 40), cpt, _60deg);
            PointF arrowR = RotatePoint(new PointF(cpt.X + 20, cpt.Y + 40), cpt, _60deg);
            PointF arrowBase = RotatePoint(new PointF(cpt.X + 10, cpt.Y + 10), cpt, _60deg);
            g.DrawLine(Pens.White, arrowTip, arrowBase);
            g.DrawLine(Pens.White, arrowTip, arrowL);
            g.DrawLine(Pens.White, arrowTip, arrowR);
        }
    }
}
